using System;

namespace SharpMud.Server.Systems.Metadata
{
	public sealed class ServerSystemMetadataEnumerator : System.Collections.IEnumerator, System.Collections.Generic.IEnumerator<IServerSystemMetadatum>
	{
		private System.Type				_ServerSystemType;
		private int						_attributeIndex;
		private IServerSystemMetadatum	_current;

		public ServerSystemMetadataEnumerator(IServerSystem serverSystem)
			:this(serverSystem.GetType())
		{
		}

		public ServerSystemMetadataEnumerator(System.Type serverSystemType)
		{
			if(AreTypesCompatible(typeof(IServerSystem),serverSystemType))
			{
				_ServerSystemType = serverSystemType;
			}
			else
			{
				throw new ArgumentException("The server system's type must be, be derived from, or implement IServerSystem.");
			}
		}

		#region IEnumerator Members

		public void Reset()
		{
			_attributeIndex = -1;
			_current = null;
		}

		object System.Collections.IEnumerator.Current
		{
			get
			{
				if(_attributeIndex<0) throw new InvalidOperationException();
				if(_attributeIndex >= _ServerSystemType.GetCustomAttributes(true).Length) throw new InvalidOperationException();
				return _current;
			}
		}

        public IServerSystemMetadatum Current
        {
            get
            {
                if (_attributeIndex < 0) throw new InvalidOperationException();
                if (_attributeIndex >= _ServerSystemType.GetCustomAttributes(true).Length) throw new InvalidOperationException();
                return _current;
            }
        }

		public bool MoveNext()
		{
			if(_attributeIndex > _ServerSystemType.GetCustomAttributes(true).Length)
			{
				return false;
			}
			_attributeIndex++;
			if(_attributeIndex >= _ServerSystemType.GetCustomAttributes(true).Length)
			{
				return false;
			}
			if( AreTypesCompatible(typeof(IServerSystemMetadatum),_ServerSystemType.GetCustomAttributes(true).GetValue(_attributeIndex).GetType()) )
			{
				_current = (IServerSystemMetadatum)_ServerSystemType.GetCustomAttributes(true).GetValue(_attributeIndex);
				return true;
			}
			else
			{
				return MoveNext();
			}
		}

		#endregion

		private static bool AreTypesCompatible(System.Type typePattern, System.Type typeCandidate)
		{
			if(typePattern==typeCandidate)
				return true;
            if(typeCandidate.IsSubclassOf(typePattern))
				return true;
			if(typePattern.IsInterface)
			{
				if(
					(new System.Collections.ArrayList(typeCandidate.GetInterfaces())).Contains(typePattern)
					)
				{
				return true;
				}
			}
			
			return false;
		}

        #region IEnumerator<IServerSystemMetadatum> Members

        IServerSystemMetadatum System.Collections.Generic.IEnumerator<IServerSystemMetadatum>.Current
        {
            get { return _current; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this._ServerSystemType = null;
            this._current = null;
            this._attributeIndex = -1;
        }

        #endregion
    }
}
